package com.wgh.pay.service.impl;

import com.wgh.pay.entity.PayLog;
import com.wgh.pay.entity.ReconciliationDiff;
import com.wgh.pay.entity.ReconciliationResult;
import com.wgh.pay.mapper.PayLogMapper;
import com.wgh.pay.mapper.ReconciliationDiffMapper;
import com.wgh.pay.mapper.ReconciliationResultMapper;
import com.wgh.pay.service.ReconciliationService;
import com.wgh.pay.vo.ReconciliationReportVO;
import com.wgh.common.vo.PageResult;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.scheduling.annotation.Scheduled;

import java.math.BigDecimal;
import java.util.*;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.logging.Logger;
import java.util.logging.Level;

/**
 * 支付对账服务实现类
 */
@Service
public class ReconciliationServiceImpl extends ServiceImpl<ReconciliationResultMapper, ReconciliationResult> implements ReconciliationService {

    private static final Logger LOGGER = Logger.getLogger(ReconciliationServiceImpl.class.getName());

    @Autowired
    private ReconciliationResultMapper reconciliationResultMapper;

    @Autowired
    private ReconciliationDiffMapper reconciliationDiffMapper;

    @Autowired
    private PayLogMapper payLogMapper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ReconciliationResult reconcile(Date reconciliationDate, Integer payType) {
        try {
            LOGGER.info("开始执行对账任务，日期：" + reconciliationDate + "，支付方式：" + payType);

            // 1. 创建对账结果记录
            ReconciliationResult result = new ReconciliationResult();
            result.setReconciliationDate(reconciliationDate);
            result.setPayType(payType);
            result.setStatus(0); // 待对账
            result.setCreateTime(LocalDateTime.now());
            result.setHandleStatus(0); // 未处理
            this.save(result);

            // 2. 获取系统支付数据
            Map<String, Object> systemPayData = getSystemPayData(reconciliationDate, payType);
            Integer systemOrderCount = (Integer) systemPayData.get("orderCount");
            BigDecimal systemPayAmount = (BigDecimal) systemPayData.get("payAmount");
            List<PayLog> systemPayLogs = (List<PayLog>) systemPayData.get("payLogs");

            // 3. 获取支付渠道数据（这里模拟实现）
            Map<String, Object> channelPayData = getChannelPayData(reconciliationDate, payType);
            Integer channelOrderCount = (Integer) channelPayData.get("orderCount");
            BigDecimal channelPayAmount = (BigDecimal) channelPayData.get("payAmount");
            List<Map<String, Object>> channelPayLogs = (List<Map<String, Object>>) channelPayData.get("payLogs");

            // 4. 比对系统数据和渠道数据，找出差异
            List<ReconciliationDiff> diffs = compareSystemAndChannelData(systemPayLogs, channelPayLogs, result.getId());

            // 5. 更新对账结果
            result.setSystemOrderCount(systemOrderCount);
            result.setSystemPayAmount(systemPayAmount);
            result.setChannelOrderCount(channelOrderCount);
            result.setChannelPayAmount(channelPayAmount);
            result.setDiffOrderCount(diffs.size());
            
            // 计算差异金额
            BigDecimal diffAmount = systemPayAmount.subtract(channelPayAmount);
            result.setDiffAmount(diffAmount);

            // 设置对账状态
            result.setStatus(diffs.isEmpty() ? 1 : 2); // 1-对账成功，2-存在差异
            result.setCompleteTime(new Date());
            this.updateById(result);

            // 6. 保存差异明细
            if (!diffs.isEmpty()) {
                for (ReconciliationDiff diff : diffs) {
                    reconciliationDiffMapper.insert(diff);
                }
            }

            LOGGER.info("对账任务执行完成，结果ID：" + result.getId() + "，差异订单数：" + diffs.size());
            return result;
        } catch (Exception e) {
            LOGGER.log(Level.SEVERE, "对账任务执行失败：" + e.getMessage(), e);
            throw new RuntimeException("对账任务执行失败：" + e.getMessage());
        }
    }

    @Override
    public PageResult<ReconciliationResult> queryReconciliationRecords(Map<String, Object> params, Integer pageNum, Integer pageSize) {
        // 实现查询对账记录的逻辑
        List<ReconciliationResult> records = reconciliationResultMapper.selectByParams(params, (pageNum - 1) * pageSize, pageSize);
        int totalCount = reconciliationResultMapper.countByParams(params);

        PageResult<ReconciliationResult> pageResult = new PageResult<>();
        pageResult.setList(records);
        pageResult.setTotal(Long.valueOf(totalCount));
        pageResult.setPageNum(pageNum);
        pageResult.setPageSize(pageSize);
        pageResult.setTotalPage(totalCount % pageSize == 0 ? totalCount / pageSize : totalCount / pageSize + 1);

        return pageResult;
    }

    @Override
    public ReconciliationReportVO generateReconciliationReport(Date startDate, Date endDate, Integer payType) {
        ReconciliationReportVO report = new ReconciliationReportVO();
        report.setStartDate(startDate);
        report.setEndDate(endDate);

        // 获取报表数据
        Map<String, Object> summaryData = getReconciliationSummary(startDate, endDate, payType);
        report.setTotalOrderCount((Integer) summaryData.get("totalOrderCount"));
        report.setTotalPayAmount((BigDecimal) summaryData.get("totalPayAmount"));
        report.setSuccessOrderCount((Integer) summaryData.get("successOrderCount"));
        report.setSuccessPayAmount((BigDecimal) summaryData.get("successPayAmount"));
        report.setDiffOrderCount((Integer) summaryData.get("diffOrderCount"));
        report.setDiffAmount((BigDecimal) summaryData.get("diffAmount"));

        // 获取按支付方式统计数据
        List<ReconciliationReportVO.PayTypeSummary> payTypeSummaries = getPayTypeSummary(startDate, endDate, payType);
        report.setPayTypeSummaries(payTypeSummaries);

        // 获取按日期统计数据
        List<ReconciliationReportVO.DateSummary> dateSummaries = getDateSummary(startDate, endDate, payType);
        report.setDateSummaries(dateSummaries);

        return report;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean handleReconciliationDiff(Long orderId, Integer status, String remark) {
        try {
            // 查询差异记录
            ReconciliationDiff diff = reconciliationDiffMapper.selectByOrderId(orderId);
            if (diff == null) {
                LOGGER.warning("未找到订单对应的对账差异记录，订单ID：" + orderId);
                return false;
            }

            // 更新差异处理状态
            diff.setHandleStatus(status);
            diff.setHandleRemark(remark);
            diff.setHandleTime(new Date());
            diff.setHandler("system"); // 实际应用中应获取当前操作用户

            boolean updateResult = reconciliationDiffMapper.updateById(diff) > 0;
            
            // 如果所有差异都已处理，更新对账结果的处理状态
            checkAndUpdateReconciliationHandleStatus(diff.getReconciliationId());
            
            return updateResult;
        } catch (Exception e) {
            LOGGER.log(Level.SEVERE, "处理对账差异失败：" + e.getMessage(), e);
            return false;
        }
    }

    @Override
    public String exportReconciliationData(Date reconciliationDate, Integer payType) {
        try {
            // 准备导出文件路径
            String exportDir = "/tmp/export/";
            File dir = new File(exportDir);
            if (!dir.exists()) {
                dir.mkdirs();
            }

            // 生成文件名
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd");
            String dateStr = formatter.format(reconciliationDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate());
            String fileName = "reconciliation_" + dateStr + (payType != null ? "_" + payType : "") + ".csv";
            String filePath = exportDir + fileName;

            // 导出数据
            try (FileWriter writer = new FileWriter(filePath)) {
                // 写入表头
                writer.write("订单ID,交易流水号,支付方式,支付金额,支付状态,支付时间\n");

                // 获取对账数据
                List<PayLog> payLogs = getPayLogsByDateAndType(reconciliationDate, payType);
                for (PayLog payLog : payLogs) {
                    writer.write(String.format("%s,%s,%s,%s,%s,%s\n",
                            payLog.getOrderId(),
                            payLog.getTransactionId(),
                            payLog.getPayType(),
                            payLog.getTotalAmount(),
                            payLog.getPayStatus(),
                            payLog.getPayTime()));
                }
            }

            LOGGER.info("对账数据导出成功，文件路径：" + filePath);
            return filePath;
        } catch (IOException e) {
            LOGGER.log(Level.SEVERE, "导出对账数据失败：" + e.getMessage(), e);
            throw new RuntimeException("导出对账数据失败：" + e.getMessage());
        }
    }

    @Override
    @Scheduled(cron = "0 0 2 * * ?")  // 每天凌晨2点执行
    public void autoReconciliationTask() {
        LOGGER.info("开始执行自动对账任务");
        try {
            // 对账日期为前一天
            Date yesterday = Date.from(LocalDate.now().minusDays(1).atStartOfDay(ZoneId.systemDefault()).toInstant());
            
            // 对所有支付方式进行对账
            for (Integer payType : Arrays.asList(1, 2, 3)) { // 1-微信支付，2-支付宝，3-银联支付
                try {
                    reconcile(yesterday, payType);
                } catch (Exception e) {
                    LOGGER.log(Level.SEVERE, "自动对账任务执行失败（支付方式：" + payType + "）：" + e.getMessage(), e);
                    // 继续处理下一个支付方式
                }
            }
            LOGGER.info("自动对账任务执行完成");
        } catch (Exception e) {
            LOGGER.log(Level.SEVERE, "自动对账任务调度失败：" + e.getMessage(), e);
        }
    }

    // 获取系统支付数据
    private Map<String, Object> getSystemPayData(Date date, Integer payType) {
        Map<String, Object> result = new HashMap<>();
        List<PayLog> payLogs = payLogMapper.selectByDateAndType(date, payType);
        
        int orderCount = payLogs.size();
        BigDecimal payAmount = BigDecimal.ZERO;
        for (PayLog payLog : payLogs) {
            payAmount = payAmount.add(payLog.getTotalAmount());
        }
        
        result.put("orderCount", orderCount);
        result.put("payAmount", payAmount);
        result.put("payLogs", payLogs);
        return result;
    }

    // 获取支付渠道数据（模拟实现）
    private Map<String, Object> getChannelPayData(Date date, Integer payType) {
        Map<String, Object> result = new HashMap<>();
        List<Map<String, Object>> channelLogs = new ArrayList<>();
        
        // 这里应该调用实际的支付渠道API获取数据
        // 这里简单模拟数据
        List<PayLog> systemLogs = payLogMapper.selectByDateAndType(date, payType);
        for (PayLog log : systemLogs) {
            Map<String, Object> channelLog = new HashMap<>();
            channelLog.put("orderId", log.getOrderId());
            channelLog.put("transactionId", log.getTransactionId());
            channelLog.put("amount", log.getTotalAmount());
            channelLog.put("payTime", log.getPayTime());
            channelLogs.add(channelLog);
        }
        
        result.put("orderCount", channelLogs.size());
        result.put("payAmount", systemLogs.stream().map(PayLog::getTotalAmount).reduce(BigDecimal.ZERO, BigDecimal::add));
        result.put("payLogs", channelLogs);
        return result;
    }

    // 比对系统数据和渠道数据
    private List<ReconciliationDiff> compareSystemAndChannelData(
            List<PayLog> systemLogs, List<Map<String, Object>> channelLogs, Long reconciliationId) {
        List<ReconciliationDiff> diffs = new ArrayList<>();
        
        // 创建映射以便快速查找
        Map<Long, PayLog> systemMap = new HashMap<>();
        for (PayLog log : systemLogs) {
            systemMap.put(log.getOrderId(), log);
        }
        
        Map<Long, Map<String, Object>> channelMap = new HashMap<>();
        for (Map<String, Object> log : channelLogs) {
            channelMap.put(Long.parseLong(log.get("orderId").toString()), log);
        }
        
        // 检查系统有但渠道没有的订单
        for (Map.Entry<Long, PayLog> entry : systemMap.entrySet()) {
            Long orderId = entry.getKey();
            PayLog systemLog = entry.getValue();
            
            if (!channelMap.containsKey(orderId)) {
                ReconciliationDiff diff = new ReconciliationDiff();
                diff.setReconciliationId(reconciliationId);
                diff.setOrderId(orderId);
                diff.setTransactionId(systemLog.getTransactionId());
                diff.setPayType(systemLog.getPayType());
                diff.setSystemAmount(systemLog.getTotalAmount());
                diff.setChannelAmount(BigDecimal.ZERO);
                diff.setDiffType(1); // 系统有渠道无
                diff.setHandleStatus(0); // 未处理
                diff.setCreateTime(LocalDateTime.now());
                diffs.add(diff);
            } else {
                // 检查金额是否一致
                Map<String, Object> channelLog = channelMap.get(orderId);
                BigDecimal channelAmount = new BigDecimal(channelLog.get("amount").toString());
                if (systemLog.getTotalAmount().compareTo(channelAmount) != 0) {
                    ReconciliationDiff diff = new ReconciliationDiff();
                    diff.setReconciliationId(reconciliationId);
                    diff.setOrderId(orderId);
                    diff.setTransactionId(systemLog.getTransactionId());
                    diff.setPayType(systemLog.getPayType());
                    diff.setSystemAmount(systemLog.getTotalAmount());
                    diff.setChannelAmount(channelAmount);
                    diff.setDiffType(3); // 金额不一致
                    diff.setHandleStatus(0); // 未处理
                    diff.setCreateTime(LocalDateTime.now());
                    diffs.add(diff);
                }
                // 从渠道映射中移除已处理的订单
                channelMap.remove(orderId);
            }
        }
        
        // 检查渠道有但系统没有的订单
        for (Map.Entry<Long, Map<String, Object>> entry : channelMap.entrySet()) {
            Long orderId = entry.getKey();
            Map<String, Object> channelLog = entry.getValue();
            
            ReconciliationDiff diff = new ReconciliationDiff();
            diff.setReconciliationId(reconciliationId);
            diff.setOrderId(orderId);
            diff.setTransactionId(channelLog.get("transactionId").toString());
            diff.setPayType(1); // 假设支付类型
            diff.setSystemAmount(BigDecimal.ZERO);
            diff.setChannelAmount(new BigDecimal(channelLog.get("amount").toString()));
            diff.setDiffType(2); // 渠道有系统无
            diff.setHandleStatus(0); // 未处理
            diff.setCreateTime(LocalDateTime.now());
            diffs.add(diff);
        }
        
        return diffs;
    }

    // 获取对账汇总数据
    private Map<String, Object> getReconciliationSummary(Date startDate, Date endDate, Integer payType) {
        return reconciliationResultMapper.getSummary(startDate, endDate, payType);
    }

    // 获取按支付方式统计数据
    private List<ReconciliationReportVO.PayTypeSummary> getPayTypeSummary(Date startDate, Date endDate, Integer payType) {
        List<Map<String, Object>> summaries = reconciliationResultMapper.getPayTypeSummary(startDate, endDate, payType);
        List<ReconciliationReportVO.PayTypeSummary> result = new ArrayList<>();
        
        for (Map<String, Object> summary : summaries) {
            ReconciliationReportVO.PayTypeSummary item = new ReconciliationReportVO.PayTypeSummary();
            item.setPayType(Integer.parseInt(summary.get("payType").toString()));
            item.setPayTypeName(getPayTypeName(Integer.parseInt(summary.get("payType").toString())));
            item.setOrderCount(Integer.parseInt(summary.get("orderCount").toString()));
            item.setPayAmount(new BigDecimal(summary.get("payAmount").toString()));
            item.setDiffCount(Integer.parseInt(summary.get("diffCount").toString()));
            item.setDiffAmount(new BigDecimal(summary.get("diffAmount").toString()));
            result.add(item);
        }
        
        return result;
    }

    // 获取按日期统计数据
    private List<ReconciliationReportVO.DateSummary> getDateSummary(Date startDate, Date endDate, Integer payType) {
        List<Map<String, Object>> summaries = reconciliationResultMapper.getDateSummary(startDate, endDate, payType);
        List<ReconciliationReportVO.DateSummary> result = new ArrayList<>();
        
        for (Map<String, Object> summary : summaries) {
            ReconciliationReportVO.DateSummary item = new ReconciliationReportVO.DateSummary();
            item.setDate((Date) summary.get("date"));
            item.setOrderCount(Integer.parseInt(summary.get("orderCount").toString()));
            item.setPayAmount(new BigDecimal(summary.get("payAmount").toString()));
            item.setDiffCount(Integer.parseInt(summary.get("diffCount").toString()));
            item.setDiffAmount(new BigDecimal(summary.get("diffAmount").toString()));
            result.add(item);
        }
        
        return result;
    }

    // 检查并更新对账结果的处理状态
    private void checkAndUpdateReconciliationHandleStatus(Long reconciliationId) {
        int unhandledCount = reconciliationDiffMapper.countUnhandledByReconciliationId(reconciliationId);
        if (unhandledCount == 0) {
            ReconciliationResult result = this.getById(reconciliationId);
            result.setHandleStatus(2); // 已处理
            result.setHandleTime(new Date());
            this.updateById(result);
        }
    }

    // 根据日期和支付方式获取支付日志
    private List<PayLog> getPayLogsByDateAndType(Date date, Integer payType) {
        return payLogMapper.selectByDateAndType(date, payType);
    }

    // 获取支付方式名称
    private String getPayTypeName(Integer payType) {
        switch (payType) {
            case 1: return "微信支付";
            case 2: return "支付宝";
            case 3: return "银联支付";
            default: return "未知";
        }
    }
}